package me.sluijsens.StartersQuiz;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import net.milkbowl.vault.economy.Economy;
import net.milkbowl.vault.permission.Permission;

import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;

/**
 * Main class for StartersQuiz
 * Managing enabling, disabling, loading files and checking players.
 * @author Bryan Slop (Sluijsens)
 *
 */
public class StartersQuiz extends JavaPlugin {
	/* Declare variables
	 * Declare listeners*/
	private final PlayerHandler playerListener = new PlayerHandler(this);
	private final BlockListener blockListener = new BlockListener(this);
	
	//Declare logger
	Logger log = Logger.getLogger("Minecraft");
	
	//Declare HashMaps
	public static Map<Player, Boolean> started = new HashMap<Player, Boolean>();
	public static Map<Player, List<Integer>> nrsQuestions = new HashMap<Player, List<Integer>>();
	public static Map<Player, Boolean> finished = new HashMap<Player, Boolean>();
	public static Map<Player, Integer> atQ = new HashMap<Player, Integer>();
	public static Map<Player, Integer> attempt = new HashMap<Player, Integer>();
	public static Map<Player, String> atQuiz = new HashMap<Player, String>();
	public static Map<String, ConfigHandler> configs = new HashMap<String, ConfigHandler>();
	public static ArrayList<String> quizzes = new ArrayList<String>();
	
	public static Permission permission = null;
	public static Economy economy = null;
	public static String tagChat;
	
	private LangHandler lang;
	/**
	 * Returns the languagehandler that will be used by the plugin.
	 * @return Returns the handler.
	 */
	public LangHandler getLangHandler() {
		return lang;
	}
	
	//Load configuration files
	private ConfigHandler conf;
	private Map<String, ConfigHandler> qConf = new HashMap<String, ConfigHandler>();
	private Map<Player, ConfigHandler> pConf = new HashMap<Player, ConfigHandler>();
	
	public int[] sort(int[] array) {
		int temp;
		
		for(int i = 0; i < array.length; i++) {
			for(int j = 1; j < array.length - i; j++) {
				if(array[j-1] > array[j]) {
					temp = array[j];
					array[j] = array[j-1];
					array[j-1] = temp;
				}
			}
		}
		
		return array;
	}
	
	public boolean in_Array(String[] array, String value) {
		int length = array.length;
		
		for(int i = 0; i < length; i++) {
			if(array[i].equalsIgnoreCase(value)) {
				return true;
			}
		}
		
		return false;
	}
	
	public boolean in_Array(Object[] array, Object value) {
		int length = array.length;
		
		for(int i = 0; i < length; i++) {
			if(array[i] == value) {
				return true;
			}
		}
		
		return false;
	}
	
	/**
	 * Returns the confighandler that will be used by the plugin to get configurations.
	 * @return Returns the confighandler.
	 */
	public ConfigHandler getConf() {
		return conf;
	}
	
	/**
	 * Returns the confighandler that will be used by the plugin to get  quiz configurations.
	 * @return Returns the confighandler
	 */
	public Map<String, ConfigHandler> getQConf() {
		return qConf;
	}
	
	/**
	 * Returns the confighandler that will be used by the plugin to get  player configurations.
	 * @return Returns the confighandler
	 */
	public Map<Player, ConfigHandler> getPConf() {
		return pConf;
	}
	
	private QuizHandler quizHandler;
	/**
	 * Returns the quizhandler that is being used.
	 * @return Returns the quizhandler
	 */
	public QuizHandler getQuizHandler() {
		return quizHandler;
	}
	
	/**
	 * Setup the permissions using from Vault
	 * @return Returns true if setup was successful
	 */
    private Boolean setupPermissions()
    {
        RegisteredServiceProvider<Permission> permissionProvider = getServer().getServicesManager().getRegistration(net.milkbowl.vault.permission.Permission.class);
        if (permissionProvider != null) {
            permission = permissionProvider.getProvider();
        }
        return (permission != null);
    }
    
    /**
	 * Setup the economy possibilities from Vault
	 * @return Returns true if setup was successful
	 */
	private boolean setupEconomy() {
        RegisteredServiceProvider<Economy> economyProvider = getServer().getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class);
        if (economyProvider != null) {
            economy = economyProvider.getProvider();
        }

        return (economy != null);
    }
	
	/**
	 * Called when plugin is enabled
	 * 
	 * Setup confighandler, languagehandler and quizhandler.
	 * Here the commands and actions are also managed and passed to the right class.
	 * Load player and quiz files and show every player his/her question when done loading.
	 */
	public void onEnable() {
		conf = new ConfigHandler("config", this.getDataFolder() + "/", this);
		lang = new LangHandler(conf.getString("Language", "en-GB"), this.getDataFolder() + "/lang", this);
		quizHandler = new QuizHandler(this);
		
		tagChat = ChatColor.AQUA + "*StartersQuiz* " + ChatColor.GOLD;
		
		if(this.getServer().getPluginManager().getPlugin("Vault") == null) {
			log.log(Level.SEVERE, "The plugin Vault ha snot been found so " + getDescription().getName() + " will be disabled.", getDescription().getName());
		} else {
			setupPermissions();
			setupEconomy();
		}
		
		//Declare the PluginManager and CommandExecutor
		PluginManager pm = this.getServer().getPluginManager();
		CmdExecutor cmdExecutor = new CmdExecutor(this);
		
		/* Register Events
		 * Register Player events*/
		pm.registerEvents(playerListener, this);
		
		//Register Block events
		pm.registerEvents(blockListener, this);
		
		//Register Command events
		getCommand("sq").setExecutor(cmdExecutor);
		getCommand("sqhelp").setExecutor(cmdExecutor);
		getCommand("sqstart").setExecutor(cmdExecutor);
		getCommand("sqquestion").setExecutor(cmdExecutor);
		getCommand("sqanswer").setExecutor(cmdExecutor);
		getCommand("sqretry").setExecutor(cmdExecutor);
		getCommand("sqreload").setExecutor(cmdExecutor);
		
		//get delay in seconds (default: 30) for the Repeating Task (showing question) and get the max attempts (default: 3)
		int seconds = conf.getInt("QuestionEveryXsec", 30);
		
		//Set those values in the config file
		if(!conf.isSet("CommandOnChat")) {
			conf.set("Language", "en-GB");
			conf.set("CommandOnChat", false);
			conf.set("QuestionsEveryXsec", seconds);
			conf.set("MaxAttempts", 3);
			conf.set("TimeOfBan", "5m");
			
			conf.set("Block.Interaction", true);
			conf.set("Block.Block-Breaking", true);
			conf.set("Block.Block-Placing", true);
			conf.set("Block.Chatting", true);
			conf.set("Block.Dropping", true);
			conf.set("Block.Picking-Up", true);
		}
		
		if(!conf.isSet("AutoStart")) {
			conf.set("AutoStart", false);
		}
		
		if(!conf.isSet("NoQuizMessage")) {
			conf.set("NoQuizMessage", true);

			//save config.yml
			if(conf.save()) log.info("[StartersQuiz] config.yml has been saved!");
			else log.warning("[StartersQuiz] config.yml could not be saved!");
		}
		
		//run the task
		this.getServer().getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {
			public void run() {
				//call the showQuestion method
				showQuestionToAll();
			}
		}, 0, seconds * 20);
		
		load();
		
		//Show in console if plugin is enabled.
		log.info(this.getDescription().getName() + " v" + this.getDescription().getVersion() + " enabled!");
	}
	
	/**
	 * Called when plugin is disabled.
	 */
	public void onDisable() {
		log.info(this.getDescription().getName() + " v" + this.getDescription().getVersion() + " disabled!");
	}
	
	/**
	 * Load (re)load config handlers, quiz and player files.
	 * @return - Returns true if loading was successful
	 */
	public boolean load() {
		boolean loading;
		conf = new ConfigHandler("config", this.getDataFolder() + "/", this);
		lang = new LangHandler(conf.getString("Language", "en-GB"), this.getDataFolder() + "/lang", this);
		quizHandler = new QuizHandler(this);
		
		loading = loadQuizzes();
		loading = loadPlayers();
		
		if(!loading) {
			log.info("Something went wrong when loading the player and quiz files. Use /sqreload to fix this.");
			return false;
		}
		return true;
	}
	
	/**
	 * Load quizzes
	 * @return Returns true if loading was successful
	 */
	public boolean loadQuizzes() {
		File dir = new File(this.getDataFolder() + "/quizzes/");
		File[] listFiles = dir.listFiles();
		
		qConf = new HashMap<String, ConfigHandler>();
		
		String quiz;
		
		for(File f: listFiles) {
			quiz = f.getName().replace(".yml", "");
			quizzes.add(quiz);
			qConf.put(quiz, new ConfigHandler(quiz, this.getDataFolder() + "/quizzes/",this));
		}
		return true;
	}
	
	/**
	 * Load all the online players
	 * @return Returns true if loading was successful
	 */
	public boolean loadPlayers() {
		for(Player player: this.getServer().getOnlinePlayers()) {
			if(!checkPlayer(player)) {
				return false;
			}
		}
		return true;
	}
	
	/**
	 * Show question to everyone who still has to answer some questions and is online.
	 */
	public void showQuestionToAll() {
		//Check all online players
		for(Player player : this.getServer().getOnlinePlayers()) {
			quizHandler.show(player);
		}
	}
	
	/**
	 * Check if the player still has to do a quiz or already succeeded.
	 * If not then load all variables and files needed to do the quiz.
	 * @param player The player who has to be checked for succession
	 * @return Returns true when player is checked
	 */
	@SuppressWarnings({ "unused", "unchecked" })
	public boolean checkPlayer(Player player) {
		String dirPlayer = this.getDataFolder() + "/players/";
		
		ConfigHandler newPlayer = new ConfigHandler(player.getName(), dirPlayer, this);
		long curTime = new Date().getTime();
		long bannedTill = newPlayer.getLong("BannedTill", 0);
		
		if((bannedTill == 0 || bannedTill < curTime) && bannedTill != -1) {
			ArrayList<String> answers = null;
			File file = new File(dirPlayer + player.getName() + ".yml");
		
			String quiz = null;
			for(String q: quizzes) {
				if(permission.has(player, "sq.quiz." + q)) {
					quiz = q;
					break;
				}
			}
			
			if(quiz == null) {
				finished.put(player, true);
				if(conf.getBoolean("NoQuizMessage", true)) player.sendMessage(tagChat + lang.getMessage("NoQuiz"));
			} else {
				if(!file.exists() || !newPlayer.isSet(quiz + ".AtQuestion")) {
					newPlayer.set(quiz + ".AtQuestion", 1);
					newPlayer.set(quiz + ".Started", false);
					newPlayer.set(quiz + ".Answers", new ArrayList<String>());
					newPlayer.set(quiz + ".Attempt", 1);
					newPlayer.set(quiz + ".Finished", false);
				}
				
				atQ.put(player, newPlayer.getInt(quiz + ".AtQuestion", 1));
				started.put(player, newPlayer.getBoolean(quiz + ".Started", false));
				answers = (ArrayList<String>) newPlayer.getList(quiz + ".Answers", new ArrayList<String>());
				attempt.put(player, newPlayer.getInt(quiz + ".Attempt", 1));
				finished.put(player, newPlayer.getBoolean(quiz + ".Finished", false));
				atQuiz.put(player, quiz);
			}
			
			pConf.put(player, newPlayer);
			
			pConf.get(player).save();
			
			if(conf.getBoolean("AutoStart") == true) {
				quizHandler.start(player);
			}
		} else {
			player.kickPlayer("You are still banned.");
		}
		return true;
	}
	
	/**
	 * Check if the player is done doing his quiz
	 * @param player The player to check
	 * @return Returns true if the player has finished
	 */
	public boolean checkDone(Player player) {
		String quiz = atQuiz.get(player);
		
		if(quiz != null) {
			if((permission.has(player, "sq.exclude." + quiz)) || finished.get(player)) return true;
			else return false;
		} else return true;
	}
	
	/**
	 * Check if the player is prohibited from doing certain actions
	 * @param player The player to check
	 * @return Returns true if player needs to be blocked.
	 */
	public boolean checkBlock(Player player) {
		String quiz = atQuiz.get(player);
		
		if(quiz != null) {
			if(!permission.has(player, "sq.exclude." + quiz) && started.get(player) || !finished.get(player) && started.get(player)) return true;
			else return false;
		} else return false;
	}
}
